package com.tn.wservice.validator;

import java.lang.reflect.Method;
import java.util.List;

/**
 * Implement me for complex values like functions on group of fields
 * 
 */
public class ComplexValueGenerator implements IValueGenerator {

	private List<ComplexValue> values;

	@Override
	public Number getValue(Object bo) throws Exception {

		Number result = 0;

		for (ComplexValue val : values) {
			result = evaluate(result, calculateValue(val, bo), val
					.getOuterFunction());
		}

		return result;
	}

	@SuppressWarnings("unchecked")
	private Number calculateValue(ComplexValue val, Object bo) throws Exception {
		Number result = 0;

		Method method = bo.getClass().getMethod(val.getGroupGetter());
		List<Object> objectList = (List<Object>) method.invoke(bo);

		for (Object obj : objectList) {
			method = obj.getClass().getMethod(val.getGetterMethod());
			result = evaluate(result, (Number) method.invoke(obj), val
					.getInnerFunction());
		}

		return result;
	}

	private Number evaluate(Number number1, Number number2, Function function) {
		Number result = 0;
		switch (function) {
		case PLUS:
			result = number1.doubleValue() + number2.doubleValue();
			break;
		case MINUS:
			result = number1.doubleValue() - number2.doubleValue();
			break;
		case MULTIPLY:
			result = number1.doubleValue() * number2.doubleValue();
			break;
		case DIVIDE:
			result = number1.doubleValue() / number2.doubleValue();
			break;
		default:
			break;
		}
		
		return result;
	}

	public void setValues(List<ComplexValue> values) {
		this.values = values;
	}

	public List<ComplexValue> getValues() {
		return values;
	}

	public enum Function {
		PLUS, MINUS, MULTIPLY, DIVIDE;
	}

	public class ComplexValue {
		private String groupGetter;
		private String getterMethod;
		private Function innerFunction;
		private Function outerFunction;

		public void setGroupGetter(String groupGetter) {
			this.groupGetter = groupGetter;
		}

		public String getGroupGetter() {
			return groupGetter;
		}

		public void setGetterMethod(String getterMethod) {
			this.getterMethod = getterMethod;
		}

		public String getGetterMethod() {
			return getterMethod;
		}

		public void setInnerFunction(Function innerFunction) {
			this.innerFunction = innerFunction;
		}

		public Function getInnerFunction() {
			return innerFunction;
		}

		public void setOuterFunction(Function outerFunction) {
			this.outerFunction = outerFunction;
		}

		public Function getOuterFunction() {
			return outerFunction;
		}
	}

}
